package com.woniu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.common.Assert;
import com.woniu.conf.RabbitConfig;
import com.woniu.enumeration.BusinessCode;
import com.woniu.enumeration.OrderStatus;
import com.woniu.mapper.AddressMapper;
import com.woniu.mapper.ItemMapper;
import com.woniu.mapper.OrderMapper;
import com.woniu.pojo.Address;
import com.woniu.pojo.Book;
import com.woniu.pojo.Item;
import com.woniu.pojo.Order;
import com.woniu.redis.RedisConst;
import com.woniu.service.AddressService;
import com.woniu.service.BookService;
import com.woniu.service.CartService;
import com.woniu.service.OrderService;
import com.woniu.vo.CartItemVo;
import com.woniu.vo.CartVo;
import com.woniu.vo.OrderItemVo;
import com.woniu.vo.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Autowired
    private BookService bookService;
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CartService cartService; // 购物车业务

    @Autowired
    private ItemMapper itemMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private AddressMapper addressMapper;

    /**
     * 生成订单
     * 1. 根据userId查询购物车信息
     * 2. 根据购物车信息生成订单
     *  2.1 判断库存是否重组
     *
     * */
    @Override
    @Transactional // 开启事务
    public String createOrder(Long userId, Integer addressId) {
        // 1. 根据userId查询购物车信息
        CartVo cartVo = cartService.getCart(userId);
        // 创建 雪花ID
        long orderId = IdUtil.getSnowflake(1, 1).nextId(); // param1: 机器码， param2: 数据中心

        // 创建 redis中hash操作对象
        HashOperations ops = redisTemplate.opsForHash();

        // 将购物车信息，生成 订单明细。将订单明细 存入 订单明细对象（Item） 中
        for (CartItemVo cartItemVo : cartVo.getItemList()) {
            // 首先判断库存是否充足
            // 获取redis库存数量
            Integer storeNum = (Integer) ops.get(RedisConst.BOOK_STORAGE, cartItemVo.getBookId().toString());
            // 库存不足，抛出异常
            Assert.error(storeNum <= cartItemVo.getQuantity(), BusinessCode.STORAGE_NOT_ENOUGH);

            // 库存充足，预减 redis库存。（java只有操作 加 方法，需要对 库存取反操作，加上 - 号）
            Long increment = ops.increment(RedisConst.BOOK_STORAGE, cartItemVo.getBookId().toString(), -cartItemVo.getQuantity()); // 预减库存

            // 生成订单明细，每个购物车项，都是一个订单明细
            Item item = new Item();
            // 填充item所有字段
            item.setBookId(cartItemVo.getBookId());
            item.setBookName(cartItemVo.getName());
            item.setPrice(cartItemVo.getPrice());
            item.setBuyCount(cartItemVo.getQuantity());
            item.setSumPrice(cartItemVo.getSum());
            item.setOrderId(orderId);
            item.setState(OrderStatus.NO_PAY.getCode());

            // 写入数据库（这里是 测试操作），后续需要 判定支付成功 ，才对数据库写操作
            itemMapper.insert(item);
        }

        // 创建订单对象
        Order order = new Order();
        // 自定义雪花 ID
        order.setId(orderId);
        order.setOrderNum("WNXY_BOOK" + orderId); // 订单编号
        order.setTotalPrice(cartVo.getTotalPrice()); // 总价
        order.setUserId(userId);
        order.setAddressId(addressId);
        order.setState(OrderStatus.NO_PAY.getCode());    // 待付款
        // 测试操作！！ 写入数据库
        orderMapper.insert(order);
        log.info("订单生成成功，订单号：{}", order.getOrderNum());

        // 异步 清空 redis购物车
        rabbitTemplate.convertAndSend("clear.cart.queue", cartVo);

        // 将订单信息发送到 死信队列，判断订单是否支付成功
        rabbitTemplate.convertAndSend("order.normal.exchange", "order.normal.routingKey", order);

        return "WNXY_BOOK" + orderId;
    }

    /**
     * 查询指定用户 的订单列表
     * 如果没有指定状态，则查询所有订单
     * */
    @Override
    public List<OrderVo> queryOrder(Long userId, Integer status) {
        // 查询指定用户订单，如果没有指定状态，查询所有订单
        LambdaQueryWrapper<Order> wrapper = Wrappers.lambdaQuery(Order.class)
                .eq(Order::getUserId, userId)
                .eq(status != null, Order::getState, status) // 这个方法意义在于，如果 status 为空，则不会拼接该条件
                .orderByDesc(Order::getCreateTime);

        // 查询订单
        List<Order> orderList = orderMapper.selectList(wrapper);

        // 将订单对象转为 订单视图对象  Order -》 OrderVo
        List<OrderVo> orderVoList = orderList.stream().map(order -> {
            // 复制订单对象属性 到OrderVo对象
            OrderVo orderVo = BeanUtil.copyProperties(order, OrderVo.class);
            // 设置独有属性
            orderVo.setStatus(order.getState());

            // 订单状态文字描述
            orderVo.setOrderStatus(OrderStatus.matchCode(order.getState()).getDescribe());

            // 查询address
            Address address = addressMapper.selectById(order.getAddressId());
            orderVo.setReceiver(address.getReceiver());
            orderVo.setPhone(address.getTelephone());
            //拼接地址信息
            orderVo.setAddress(address.getProvince() + address.getCity() + address.getArea() + address.getDetailAddress());
            orderVo.setUserId(String.valueOf(userId)); // OrderVo中的userId是String类型

            // 订单明细
            List<Item> itemList = itemMapper.selectList(Wrappers.lambdaQuery(Item.class)
                    .eq(Item::getOrderId, order.getId()));

            // 订单明细转为订单视图对象 Item --》 OrderItemVo
            List<OrderItemVo> itemVoList = itemList.stream().map(item -> {
                OrderItemVo itemVo = BeanUtil.copyProperties(item, OrderItemVo.class);
                // 根据图书id，查询图书，获取图书图片地址
                Book book = bookService.findById(item.getBookId());
                itemVo.setBookImg(book.getImgSrc());
                return itemVo;
            }).collect(Collectors.toList());

            // 添加订单项 到订单属性
            orderVo.setOrderItem(itemVoList);

            return orderVo;
        }).collect(Collectors.toList());


        return orderVoList;
    }

}

























